﻿using Microsoft.AspNetCore.Authorization;
using Microsoft.Extensions.Options;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Threading.Tasks;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services;
using Volo.Abp.LanguageManagement.Dto;
using Volo.Abp.Localization;
using Volo.Abp.ObjectExtending;
using Volo.Abp.SettingManagement;

namespace Volo.Abp.LanguageManagement
{
    [Authorize(LanguageManagementPermissions.Languages.Default)]
	public class LanguageAppService : LanguageAppServiceBase, IRemoteService, IApplicationService, ILanguageAppService
	{
		protected ISettingManager SettingManager { get; }

		protected ILanguageRepository LanguageRepository { get; }

		protected AbpLocalizationOptions AbpLocalizationOptions { get; }

		public LanguageAppService(ISettingManager settingManager, IOptions<AbpLocalizationOptions> abpLocalizationOptions, ILanguageRepository languageRepository)
		{
			this.SettingManager = settingManager;
			this.LanguageRepository = languageRepository;
			this.AbpLocalizationOptions = abpLocalizationOptions.Value;
		}

		public virtual async Task<ListResultDto<LanguageDto>> GetAllListAsync()
		{
			var languages = await this.LanguageRepository.GetListAsync(false);
			var defaultLanguage = await this.FindDefaultLanguage(languages);
			var list = base.ObjectMapper.Map<List<Language>, List<LanguageDto>>(languages);
			if (defaultLanguage != null)
			{
				var languageDto = list.Find(l => l.CultureName == defaultLanguage.CultureName && l.UiCultureName == defaultLanguage.CultureName);
				if (languageDto != null)
				{
					languageDto.IsDefaultLanguage = true;
				}
			}
			return new ListResultDto<LanguageDto>(list);
		}

		public async Task<ListResultDto<LanguageDto>> GetListAsync(GetLanguagesTextsInput input)
		{
			var languages = await this.LanguageRepository.GetListAsync(false);
			var list = base.ObjectMapper.Map<List<Language>, List<LanguageDto>>(languages);
			var queryable = list.AsQueryable<LanguageDto>();
			bool flag = !input.Filter.IsNullOrWhiteSpace();
			queryable.WhereIf<LanguageDto>(flag, x =>
				 (x.UiCultureName != null && x.UiCultureName.IndexOf(input.Filter) >= 0) ||
				 (!input.GetOnlyEmptyValues && x.CultureName != null && x.CultureName.IndexOf(input.Filter) >= 0)
			 );
			var result = queryable.ToList();
			return await Task.FromResult<ListResultDto<LanguageDto>>(new ListResultDto<LanguageDto>(result));
		}

		[Authorize(LanguageManagementPermissions.Languages.Delete)]
		public virtual async Task DeleteAsync(Guid id)
		{
			await this.LanguageRepository.DeleteAsync(id);
		}

		[Authorize(LanguageManagementPermissions.Languages.ChangeDefault)]
		public virtual async Task SetAsDefaultAsync(Guid id)
		{
			var result = await this.LanguageRepository.GetAsync(id);
			await this.SettingManager.SetForCurrentTenantAsync("Abp.Localization.DefaultLanguage", result.CultureName + ";" + result.UiCultureName, false);
		}

		[Authorize(LanguageManagementPermissions.Languages.Create)]
		public virtual async Task<LanguageDto> CreateAsync(CreateLanguageDto input)
		{
			var language = new Language(base.GuidGenerator.Create(), input.CultureName, input.UiCultureName, input.DisplayName, input.FlagIcon, input.IsEnabled);
			input.MapExtraPropertiesTo<CreateLanguageDto, Language>(language);
			language = await this.LanguageRepository.InsertAsync(language);
			return base.ObjectMapper.Map<Language, LanguageDto>(language);
		}

		public virtual async Task<LanguageDto> GetAsync(Guid id)
		{
			var result = await this.LanguageRepository.GetAsync(id);
			var languageDto = base.ObjectMapper.Map<Language, LanguageDto>(result);
			var flag = await this.IsDefaultLanguage(result);
			languageDto.IsDefaultLanguage = flag;
			return languageDto;
		}

		[Authorize(LanguageManagementPermissions.Languages.Edit)]
		public virtual async Task<LanguageDto> UpdateAsync(Guid id, UpdateLanguageDto input)
		{
			var language = await this.LanguageRepository.GetAsync(id);
			language.SetDisplayName(input.DisplayName);
			language.FlagIcon = input.FlagIcon;
			language.IsEnabled = input.IsEnabled;
			input.MapExtraPropertiesTo<UpdateLanguageDto, Language>(language);
			await this.LanguageRepository.UpdateAsync(language);
			return base.ObjectMapper.Map<Language, LanguageDto>(language);
		}

		public virtual Task<List<LanguageResourceDto>> GetResourcesAsync()
		{
			return Task.FromResult<List<LanguageResourceDto>>((from r in this.AbpLocalizationOptions.Resources.Values
															   select new LanguageResourceDto
															   {
																   Name = r.ResourceName
															   }).ToList<LanguageResourceDto>());
		}

		public virtual async Task<List<CultureInfoDto>> GetCulturelistAsync()
		{
			return await Task.FromResult<List<CultureInfoDto>>((from c in CultureInfo.GetCultures(CultureTypes.AllCultures)
																select new CultureInfoDto
																{
																	DisplayName = c.DisplayName,
																	Name = c.Name
																}).ToList<CultureInfoDto>());
		}

		protected virtual async Task<Language> FindDefaultLanguage(List<Language> languages)
		{
			string text = await this.SettingManager.GetOrNullForCurrentTenantAsync("Abp.Localization.DefaultLanguage");
			Language result;
			if (text.IsNullOrEmpty())
			{
				result = null;
			}
			else
			{
				ValueTuple<string, string> valueTuple = LocalizationSettingHelper.ParseLanguageSetting(text);
				string item = valueTuple.Item1;
				string item2 = valueTuple.Item2;
				result = languages.FindByCulture<Language>(item, item2);
			}
			return result;
		}

		protected virtual async Task<bool> IsDefaultLanguage(Language language)
		{
			string text = await this.SettingManager.GetOrNullForCurrentTenantAsync("Abp.Localization.DefaultLanguage");
			bool result;
			if (text.IsNullOrEmpty())
			{
				result = false;
			}
			else
			{
				ValueTuple<string, string> valueTuple = LocalizationSettingHelper.ParseLanguageSetting(text);
				string item = valueTuple.Item1;
				string item2 = valueTuple.Item2;
				result = (language.CultureName == item && language.UiCultureName == item2);
			}
			return result;
		}
	}
}
